package com.qt.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qt.common.LanguageScriptEnum;
import com.qt.config.JudgeEnvironmentConfig;
import com.qt.enums.ApiExceptionEnum;
import com.qt.judge.JudgeCompiler;
import com.qt.judge.JudgeConfiguration;
import com.qt.judge.JudgeHolder;
import com.qt.judge.JudgeRun;
import com.qt.mapper.JudgeMapper;
import com.qt.pojo.dto.SingleJudgeResultDTO;
import com.qt.pojo.dto.ToJudgeDTO;
import com.qt.pojo.entity.judge.Judge;
import com.qt.pojo.entity.problem.Problem;
import com.qt.result.R;
import com.qt.service.JudgeService;
import com.qt.service.ProblemService;
import com.qt.utils.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

/**
 * @author pgw
 * @version 1.0
 * @description
 * @date Create by 2023/9/30 16:15
 */
@Service
@Slf4j(topic = "qtoj")
public class JudgeServiceImpl  extends ServiceImpl<JudgeMapper, Judge>  implements JudgeService {

    @Autowired
    private  JudgeMapper judgeMapper;

    @Autowired
    private ProblemService problemService;

    @Autowired
    private JudgeEnvironmentConfig judgeEnvironmentConfig;




    @Override
    public void compile(Judge judge) {
        //进入编译阶段
        boolean isOk =  judgeMapper.updateStatus(Constants.Judge.STATUS_COMPILING.getStatus() ,judge.getId());

        Problem problem = problemService.getById(judge.getProblemId());
         log.debug("开始编译.........");
         initCompile(judge);
        JudgeCompiler.compile(judge);

        

    }


    @Override
    public R run(ToJudgeDTO toJudgeDTO) {

        initCompile(toJudgeDTO.getJudge());
        List<String> compileResult = JudgeCompiler.compile(toJudgeDTO.getJudge());
        SingleJudgeResultDTO singleJudgeResultDTO = null;
        if(isCompileSuccess(compileResult)){
            //编译通过
            singleJudgeResultDTO = JudgeRun.run("/home/judge/submission/Main.in");
        }
        if(singleJudgeResultDTO == null){
            return  R.error(Constants.Judge.STATUS_SYSTEM_ERROR.getName());
        }
        log.debug("stdOutPath:{}" , singleJudgeResultDTO.getStdOutPath());
         Boolean isRunSuccess = singleJudgeResultDTO.getCondition() == 1;
         Boolean isAccept = compareOutputWithResolutions(singleJudgeResultDTO.getStdOutPath() , "/home/judge/submission/exe.out");;
         if(isRunSuccess && isAccept){
             log.debug("accept");
         }else{
             log.debug("error!  ");
         }
         return R.success(singleJudgeResultDTO);
    }

    private Boolean compareOutputWithResolutions(String submissionOutput, String expectedOutput) {
        String exitCode = "0";
        try {
            String compareScript = JudgeHolder.getCompareScriptPath();

            Process process = JudgeHolder.getRunner().exec(new String[]{
                    compareScript,
                    submissionOutput,
                    expectedOutput
            });
            process.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            exitCode = reader.readLine();
        } catch (IOException | InterruptedException ioException) {
            // TODO：异常处理
            ioException.printStackTrace();
        }
        return "0".equals(exitCode);
    }

    private  void initCompile(Judge judge){
        JudgeConfiguration judgeConfiguration =
                new JudgeConfiguration(judgeEnvironmentConfig.getSubmissionPath(),
                                       judgeEnvironmentConfig.getScriptPath() ,
                                       judge.getId());

        JudgeHolder.initJudgeConfiguration(judgeConfiguration);

    }


    private Boolean isCompileSuccess(List<String> compileResult) {
        LanguageScriptEnum language = LanguageScriptEnum.toLanguageType(JudgeHolder.getJudgeConfiguration().getLanguage());
        // c语言家族（c && cpp）
        boolean isCppFamily = (language == LanguageScriptEnum.C || language == LanguageScriptEnum.C_PLUS_PLUS);
        // java
        boolean isJava = (language == LanguageScriptEnum.JAVA);
        // 另外，python 属于解释性语言，不在此处考虑
        for (String str : compileResult) {
            boolean isBad = str.contains("error:") || str.contains("错误：") || str.contains("Error:");
            if (isCppFamily && isBad) {
                return false;
            }
            if (isJava && isBad) {
                return false;
            }
        }
        return true;
    }

}
